//
// Created by mio on 25-4-23.
//

#ifndef RTMPCONNECTION_H
#define RTMPCONNECTION_H

#include <netinet/in.h>

#include "../Net/TcpConnection.h"
#include "amf.h"
#include "RtmpSink.h"
#include "RtmpChunk.h"
#include "RtmpHandshake.h"

class RtmpServer;
class RtmpSession;
class Rtmp;

/**
 * @class RtmpConnection
 * @brief 代表一个完整的 RTMP 客户端连接。
 *
 * 该类继承自 TcpConnection (处理底层 TCP I/O 和事件) 和 RtmpSink (表示它可以作为媒体数据的消费者，即播放器)。
 * 它负责处理 RTMP 协议的完整流程，包括：
 * - 握手 (Handshake)
 * - RTMP Chunk 的解析与封装 (Chunking)
 * - RTMP 消息的处理 (Command, Data, Audio, Video, Control)
 * - AMF0 命令的编解码与处理 (connect, createStream, publish, play 等)
 * - 与 RtmpServer 和 RtmpSession 交互，管理流的发布和订阅。
 * - 作为 RtmpSink，接收并发送（给客户端）媒体数据。
 */
class RtmpConnection : public TcpConnection, public RtmpSink
{
public:
    enum ConnectionState
    {
        HANDSHAKE,
        START_CONNECT,
        START_CREATE_STREAM,
        START_DELETE_STREAM,
        START_PLAY,
        START_PUBLISH,
    };

    RtmpConnection(std::shared_ptr<RtmpServer> rtmp_server, TaskScheduler* scheduler, int sockfd);
    virtual ~RtmpConnection();

    virtual bool IsPlayer() override { return state_ == START_PLAY; }
    virtual bool IsPublisher() override { return state_ == START_PUBLISH; }
    virtual bool IsPlaying() override { return is_playing_; }
    virtual bool IsPublishing() override { return is_publishing_; }
    virtual uint32_t GetId() override { return this->GetSocket(); }

private:
    RtmpConnection(TaskScheduler* scheduler, int sockfd, Rtmp* rtmp);

    bool OnRead(BufferReader& buffer);
    void OnClose();

    /* --- RTMP 消息处理流程 --- */
    /**
     * @brief 从缓冲区解析 RTMP Chunk，并驱动消息处理。
     * @param buffer 输入数据缓冲区。
     * @return bool 是否处理成功。
     */
    bool HandleChunk(BufferReader& buffer);
    /**
     * @brief 分发处理一个完整的 RTMP 消息。
     * @param rtmp_msg 解析出的 RtmpMessage 对象。
     * @return bool 是否处理成功。
     */
    bool HandleMessage(RtmpMessage& rtmp_msg);
    /**
     * @brief 处理 RTMP 命令消息 (Invoke, Type 20/17)。
     * @param rtmp_msg 命令消息。
     * @return bool 是否处理成功。
     */
    bool HandleInvoke(RtmpMessage& rtmp_msg);
    /**
     * @brief 处理 RTMP 数据消息 (Notify, Type 18/15)，主要是 onMetaData。
     * @param rtmp_msg 数据消息。
     * @return bool 是否处理成功。
     */
    bool HandleNotify(RtmpMessage& rtmp_msg);
    /**
     * @brief 处理 RTMP 音频消息 (Type 8)。
     * @param rtmp_msg 音频消息。
     * @return bool 是否处理成功。
     */
    bool HandleAudio(RtmpMessage& rtmp_msg);
    /**
     * @brief 处理 RTMP 视频消息 (Type 9)。
     * @param rtmp_msg 视频消息。
     * @return bool 是否处理成功。
     */
    bool HandleVideo(RtmpMessage& rtmp_msg);

    /* --- 具体 RTMP 命令处理 --- */
    /**
     * @brief 处理客户端的 connect 命令。
     * @return bool 是否处理成功。
     */
    bool HandleConnect();
    /**
     * @brief 处理客户端的 createStream 命令。
     * @return bool 是否处理成功。
     */
    bool HandleCreateStream();
    /**
     * @brief 处理客户端的 publish 命令。
     * @return bool 是否处理成功。
     */
    bool HandlePublish();
    /**
     * @brief 处理客户端的 play 命令。
     * @return bool 是否处理成功。
     */
    bool HandlePlay();
    /**
     * @brief 处理客户端的 deleteStream 命令 (或连接断开时的清理)。
     * @return bool 是否处理成功。
     */
    bool HandleDeleteStream();


    /* --- RTMP 协议控制消息发送 --- */
    /**
     * @brief 发送 Set Peer Bandwidth 协议控制消息。
     */
    void SetPeerBandWidth();
    /**
     * @brief 发送 Window Acknowledgement Size 协议控制消息。
     */
    void SendAcknowledgement();
    /**
     * @brief 发送 Set Chunk Size 协议控制消息。
     */
    void SetChunkSize();

    // --- 消息发送辅助函数 ---
    /**
     * @brief 发送一个 Invoke (命令) 消息。
     * @param csid 要使用的 Chunk Stream ID。
     * @param payload 编码好的 AMF0/AMF3 负载。
     * @param payload_size 负载大小。
     * @return bool 是否发送成功。
     */
    bool SendInvokeMessage(uint32_t csid,std::shared_ptr<char> payload,uint32_t payload_size);
    /**
     * @brief 发送一个 Notify (数据) 消息。
     * @param csid 要使用的 Chunk Stream ID。
     * @param payload 编码好的 AMF0/AMF3 负载。
     * @param payload_size 负载大小。
     * @return bool 是否发送成功。
     */
    bool SendNotifyMessage(uint32_t csid,std::shared_ptr<char> payload,uint32_t payload_size);
    /**
     * @brief 检查给定的视频数据是否是 H.264 关键帧。
     * @param data 视频帧负载数据。
     * @param size 负载大小。
     * @return bool 如果是 H.264 关键帧则返回 true。
     */
    bool IsKeyFrame(std::shared_ptr<char> data, uint32_t size);
    /**
     * @brief 将一个 RtmpMessage 打包成 Chunk 并发送出去。
     * @param csid 要使用的 Chunk Stream ID。
     * @param rtmp_msg 要发送的 RtmpMessage。
     */
    void SendRtmpChunks(uint32_t csid,RtmpMessage& rtmp_msg);

    /* --- RtmpSink 接口实现 --- */
    /* 供RtmpSession调用 */
    /**
     * @brief 作为 Sink (播放器连接) 发送元数据给客户端。
     * @param metaData 元数据 Map。
     * @return bool 是否发送成功。
     */
    bool SendMetaData(AmfObjects metaData) override;
    /**
     * @brief 作为 Sink (播放器连接) 发送媒体数据给客户端。
     * @param type 数据类型。
     * @param timestamp 时间戳。
     * @param payload 媒体数据负载。
     * @param payload_size 负载大小。
     * @return bool 是否发送成功。
     */
    bool SendMediaData(uint8_t type, uint64_t timestamp, std::shared_ptr<char> payload, uint32_t payload_size) override;

private:
    ConnectionState state_;
    std::shared_ptr<RtmpHandshake> handshake_;
    std::shared_ptr<RtmpChunk> rtmp_chunk_;

    std::weak_ptr<RtmpServer> rtmp_server_;
    std::weak_ptr<RtmpSession> rtmp_session_;

    uint32_t peer_width_ = 5000000;
    uint32_t acknowledgement_size_ = 5000000;
    uint32_t max_chunk_size_ = 128;
    uint32_t stream_id_ = 0;

    AmfObjects meta_data_;
    AmfDecoder amf_decoder_;
    AmfEncoder amf_encoder_;

    bool is_playing_ = false;
    bool is_publishing_ = false;

    std::string app_;
    std::string stream_name_;
    std::string stream_path_;

    bool has_key_frame = false;

    // 元数据
    std::shared_ptr<char> avc_sequence_header_;
    std::shared_ptr<char> aac_sequence_header_;
    uint32_t avc_sequence_header_size_ = 0;
    uint32_t aac_sequence_header_size_ = 0;
};



#endif //RTMPCONNECTION_H
